/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package compilador;

import compilador.pojo.Mensagem;
import compilador.pojo.MensagemErro;
import compilador.pojo.Token;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

/**
 *
 * @author H
 */
public class AnalisadorLexical {

    private final int lexico = 1;
    private String codigoFonte;
    private int posicaoProximoCaractere;
    private int numeroLinha;
    private char charLido;
    private boolean criarArquivoTokens;

    /**
     *
     * @param codigoFonte
     */
    public AnalisadorLexical(String codigoFonte) {

        this.criarArquivoTokens = true;
        this.posicaoProximoCaractere = -1;
        this.numeroLinha = 1;
        this.codigoFonte = codigoFonte;
        this.pegaProximoCaractere();
    }

    /**
     *
     * @return Token
     */
    public Object pegaToken() {


        if (!this.fimDoCodigo() && this.consomeEspacoEComentario()) {

            Token token;


            if (Character.isDigit(this.charLido)) {

                token = this.trataDigito();
            } else if (Character.isLetter(this.charLido)) {

                token = this.trataIdentificadorEPalavraReservada();
            } else if (this.charLido == ':') {

                token = this.trataAtribuicao();
            } else if (this.charLido == '+' || this.charLido == '-' || this.charLido == '*') {

                token = this.trataOperadorAritmetico();
            } else if (this.charLido == '<' || this.charLido == '>' || this.charLido == '=') {

                token = this.trataOperadorRelacional();
            } else if (this.charLido == ';' || this.charLido == ',' || this.charLido == '.' || this.charLido == '(' || this.charLido == ')') {

                token = this.trataPontuacao();
            } else {

                //System.err.println("ERRO LEXICAL - MÉTODO PEGA TOKEN - O CARACTERE É INVÁLIDO.\'" + this.charLido + "\'  - pegaToken(): LINHA:" + this.numeroLinha);

                //System.err.println( "asdfasdf:" + this.numeroLinha );
                return new MensagemErro(this.lexico, this.numeroLinha, "O CARACTERE É INVÁLIDO.\'" + this.charLido + "\' LINHA:" + this.numeroLinha);

            }

            //this.pegaProximoCaractere();
            this.salvarTokenArquivo(token);
            return token;
        } else {

            //System.out.println( this.numeroLinha );
            return new Mensagem("LÉXICAL CONCLUIDO COM SUCESSO.");
        }
    }

    private void salvarTokenArquivo(Token token) {

        //System.out.println(token.toString());
        FileWriter writer;

        try {
            if (this.criarArquivoTokens == true) {
                writer = new FileWriter("tokensLidos.txt");
                this.criarArquivoTokens = false;
            } else {
                writer = new FileWriter("tokensLidos.txt", true);
            }

            PrintWriter print = new PrintWriter(writer, true);
            print.println(token.toString());
            print.flush();


        } catch (IOException e) {
            System.err.println("Erro ao manipular arquivo.");
        }
    }

    /**
     *
     * @return continuaExecucao
     */
    private boolean consomeEspacoEComentario() {

        boolean continuaExecucao = false;


        //CONSOME ESPAÇO 
        while (Character.isSpaceChar(this.charLido) || this.charLido == '{' || this.charLido == '\n' || this.charLido == '\t') {


            if (this.charLido == '{') {

                while (this.charLido != '}') {

                    if (this.charLido == '\n') {
                        this.numeroLinha++;
                    }
                    if (!this.pegaProximoCaractere()) {
                        return continuaExecucao;
                    }
                }
            }

            if (this.charLido == '\n') {
                this.numeroLinha++;
            }

            if (!this.pegaProximoCaractere()) {
                return continuaExecucao;
            }

        }

        return true;

    }

    private Token trataDigito() {


        String num = "";

        while (Character.isDigit(this.charLido)) {

            num += String.valueOf(this.charLido);
            this.pegaProximoCaractere();
        }

        return new Token(num, "Snumero");


    }

    private Token trataIdentificadorEPalavraReservada() {

        String lexema;
        Token token = new Token();
        lexema = String.valueOf(this.charLido);
        this.pegaProximoCaractere();

        while (Character.isDigit(this.charLido) || Character.isLetter(this.charLido) || this.charLido == '_') {


            lexema += String.valueOf(this.charLido);
            this.pegaProximoCaractere();
        }

        token.setLexema(lexema);

        switch (lexema.toLowerCase()) {

            case "programa":

                token.setSimbolo("Sprograma");
                break;
            case "se":

                token.setSimbolo("Sse");
                break;
            case "entao":

                token.setSimbolo("Sentao");
                break;
            case "senao":

                token.setSimbolo("Ssenao");
                break;
            case "enquanto":

                token.setSimbolo("Senquanto");
                break;
            case "faca":

                token.setSimbolo("Sfaca");
                break;
            case "inicio":

                token.setSimbolo("Sinicio");
                break;
            case "fim":

                token.setSimbolo("Sfim");
                break;
            case "escreva":

                token.setSimbolo("Sescreva");
                break;
            case "leia":

                token.setSimbolo("Sleia");
                break;
            case "var":

                token.setSimbolo("Svar");
                break;
            case "inteiro":

                token.setSimbolo("Sinteiro");
                break;
            case "booleano":

                token.setSimbolo("Sbooleano");
                break;
            case "verdadeiro":

                token.setSimbolo("Sverdadeiro");
                break;
            case "falso":

                token.setSimbolo("Sfalso");
                break;
            case "procedimento":

                token.setSimbolo("Sprocedimento");
                break;
            case "funcao":

                token.setSimbolo("Sfuncao");
                break;
            case "div":

                token.setSimbolo("Sdiv");
                break;
            case "e":

                token.setSimbolo("Se");
                break;
            case "ou":

                token.setSimbolo("Sou");
                break;
            case "nao":

                token.setSimbolo("Snao");
                break;
            default:
                token.setSimbolo("Sidentificador");

        }

        return token;
    }

    private Token trataAtribuicao() {

        Token token = new Token();
        String lexema = String.valueOf(this.charLido);

        this.pegaProximoCaractere();

        if (this.charLido == '=') {
            token.setSimbolo("Satribuicao");
            lexema += String.valueOf(this.charLido);
            this.pegaProximoCaractere();
        } else {
            token.setSimbolo("Sdoispontos");
        }

        token.setLexema(lexema);

        return token;
    }

    private Token trataOperadorAritmetico() {

        Token token = new Token();
        String lexema = String.valueOf(this.charLido);
        token.setLexema(lexema);

        switch (lexema.toLowerCase()) {

            case "+":

                token.setSimbolo("Smais");
                break;

            case "-":

                token.setSimbolo("Smenos");
                break;
            case "*":

                token.setSimbolo("Smult");
                break;
        }

        this.pegaProximoCaractere();
        return token;
    }

    private Token trataOperadorRelacional() {


        Token token = new Token();
        String lexema = String.valueOf(this.charLido);
        
        this.pegaProximoCaractere();

        switch (lexema.toLowerCase()) {

            case ">":
                
                if (this.charLido == '=') {

                    lexema += String.valueOf(this.charLido);
                    token.setSimbolo("Smaiorig");
                    this.pegaProximoCaractere();
                } else {

                    token.setSimbolo("Smaior");
                }
                break;

            case "<":
                
                if (this.charLido == '=') {

                    lexema += String.valueOf(this.charLido);
                    token.setSimbolo("Smenorig");
                    this.pegaProximoCaractere();
                } else if( this.charLido == '>'){
  
                    lexema += String.valueOf(this.charLido);
                    token.setSimbolo("Sdif");
                    this.pegaProximoCaractere();                
                }else {

                    token.setSimbolo("Smenor");
                }
                
                break;
            case "=":

                token.setSimbolo("Sigual");
                break;
        }

        token.setLexema(lexema);
        return token;
    }

    private Token trataPontuacao() {

        Token token = new Token();
        String lexema = String.valueOf(this.charLido);
        token.setLexema(lexema);

        switch (lexema.toLowerCase()) {

            case ";":

                token.setSimbolo("Sponto_virgula");
                break;

            case ",":

                token.setSimbolo("Svirgula");
                break;
            case "(":

                token.setSimbolo("Sabre_parenteses");
                break;
            case ")":

                token.setSimbolo("Sfecha_parenteses");
                break;
            case ".":

                token.setSimbolo("Sponto");
                break;
        }

        this.pegaProximoCaractere();
        return token;
    }

    /*========================================================================*/
    /**
     *
     * @return
     */
    public int getNumeroLinha() {
        return numeroLinha;
    }
    
    public void setNumeroLinha(int numeroLinha){
        
        this.numeroLinha = numeroLinha;
    }

    /**
     *
     * @return fim do código
     */
    private boolean fimDoCodigo() {

        if (this.codigoFonte.length() > this.posicaoProximoCaractere) {
            return false;
        } else {
            return true;
        }
    }

    /**
     *
     * @return true se houver proximo caractere.
     */
    private boolean pegaProximoCaractere() {

        this.posicaoProximoCaractere++;
        if (!this.fimDoCodigo()) {

            this.charLido = this.codigoFonte.charAt(this.posicaoProximoCaractere);
            return true;
        }
        return false;
    }
    /**
     * ***********************************************************************
     */
    /*private String getLexema() {


     if (!this.fimDoCodigo()) {
     char ch = this.codigoFonte.charAt(this.proximoCaractere);
     String lexema = "";






     do {

     lexema += String.valueOf(ch);
     this.proximoCaractere++;
     ch = this.codigoFonte.charAt(this.proximoCaractere);


     } while ((Character.isDigit(ch) || Character.isLetter(ch)) && this.codigoFonte.length() > this.proximoCaractere);


     return lexema;
     } else {
     return null;
     }
     }

     private boolean pegaCaractere() {

     this.proximoCaractere++;

     if (!this.fimDoCodigo()) {


     this.charLido = this.codigoFonte.charAt(this.proximoCaractere);

     while ((!Character.isLetter(this.charLido) || !Character.isDigit(this.charLido)) && !this.fimDoCodigo()) {


     this.proximoCaractere++;
     this.charLido = this.codigoFonte.charAt(this.proximoCaractere);
     }


     }


     return false;
     }
     */
}
